package com.bibrApp.difu.fragment.send_mvp;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.bibrApp.difu.BeemIntent;
import com.bibrApp.difu.DfApp;
import com.bibrApp.difu.R;
import com.bibrApp.difu.base.BaseFragment;
import com.bibrApp.difu.dialog.InputPinDialog;
import com.bibrApp.difu.proto2javabean.UtxoBean;
import com.bibrApp.difu.utils.BigdecimalUtils;
import com.bibrApp.difu.utils.ClsPublicUtils;
import com.bibrApp.difu.utils.DialogUtils;
import com.bibrApp.difu.utils.Protocol;
import com.bibrApp.difu.utils.ToastUtils;
import com.bibrApp.difu.utils.UCaculateUtils;
import com.bibrApp.difu.utils.UsbConnectUtils;
import com.bibrApp.difu.widget.DFDialog;
import com.bibrApp.difu.widget.HorizontalDividerItemDecoration;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.googlecode.protobuf.format.JsonFormat;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessageBitcoin;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessageCommon;
import com.satoshilabs.trezor.lib.protobuf.TrezorMessageEthereum;

import org.web3j.protocol.Web3j;
import org.web3j.protocol.Web3jFactory;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.OnClick;

import static android.util.Base64.encodeToString;

public class SendFragment extends BaseFragment<SendPresenter> implements ISendView {

    @BindView(R.id.recycler_view)
    RecyclerView recyclerView;
    @BindView(R.id.tv_low)
    TextView tv_low;
    @BindView(R.id.tv_mid)
    TextView tv_mid;
    @BindView(R.id.tv_hig)
    TextView tv_hig;
    @BindView(R.id.tv_send_title)
    TextView tv_send_title;
    @BindView(R.id.btn_add)
    ImageView IvAdd;
    //eth
    @BindView(R.id.rl_eth)
    RelativeLayout rl_eth;
    @BindView(R.id.tv_addr)
    TextView ethAddress;
    @BindView(R.id.tv_eth)
    EditText ethNum;
    @BindView(R.id.tv_gs)
    EditText gsNum;
    private SendAdapter adapter;
    private MySendAdapter mySendAdapter;
    private UsbManager usbManager;//usb管理器
    private UsbDevice mUsbDevice;//找到的usb设备
    private UsbInterface mUsbInterface;
    private UsbDeviceConnection mUsbDeviceConnection;
    private Context mContext;
    private DfApp dfApp;
    private List<SendBean> list = new ArrayList<>();
    private int fee = 24;
    private String coinType = "btc";
    private UpdataCoinTypeReceiver mUpdataReceiver;

    @Override
    protected int getLayoutResId() {
        return R.layout.fragment_send;
    }

    @Override
    protected void initPresenter() {
        presenter = new SendPresenter(getContext(), this);
        presenter.init();
    }

    @Override
    public void error(String msg) {

    }

    private List<UtxoBean> mUtxoBeanList;

    @Override
    public void successOfUtxo(List<UtxoBean> utxoBeanList) {
        mUtxoBeanList = utxoBeanList;
    }

    @Override
    public void initView() {
        mContext = getContext();
        dfApp = (DfApp) getActivity().getApplication();
        mUpdataReceiver = new UpdataCoinTypeReceiver();

        changeView();
        mContext.registerReceiver(mUpdataReceiver, new IntentFilter(BeemIntent.ACTION_UPDATE_CION_TYPE_INTENT));
        usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(mContext)
                .color(getResources().getColor(R.color.black_f0))
                .margin(12)
                .build());
        mySendAdapter = new MySendAdapter(mContext);
        recyclerView.setAdapter(mySendAdapter);
        list.add(0, new SendBean());
        mySendAdapter.setData(list);
        presenter.getBtcUtxo(dfApp.getXpub());
        checkUsb();
    }

    private void changeView() {
        if(coinType == null){
            return;
        }
        if (coinType.equalsIgnoreCase("eth")) {
            recyclerView.setVisibility(View.GONE);
            tv_send_title.setText("发送ETH");
            tv_low.setText("低\n5GWei/E");
            tv_mid.setText("中\n10GWei/E");
            tv_hig.setText("高\n20GWei/E");
            IvAdd.setVisibility(View.GONE);
            rl_eth.setVisibility(View.VISIBLE);
        } else {
            tv_send_title.setText("发送BTC");
            recyclerView.setVisibility(View.VISIBLE);
            tv_low.setText("低\n12Sat/B");
            tv_mid.setText("中\n24Sat/B");
            tv_hig.setText("高\n48Sat/B");
            IvAdd.setVisibility(View.VISIBLE);
            rl_eth.setVisibility(View.GONE);
        }
    }

    @OnClick(R.id.tv_low)
    public void clickLowFee() {
        if(coinType.equalsIgnoreCase("eth")){
            fee = 5;
        }else{
            fee = 12;
        }
        tv_low.setBackgroundColor(mContext.getResources().getColor(R.color.blue_e4));
        tv_mid.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        tv_hig.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        tv_low.setTextColor(mContext.getResources().getColor(R.color.white));
        tv_mid.setTextColor(mContext.getResources().getColor(R.color.black_3));
        tv_hig.setTextColor(mContext.getResources().getColor(R.color.black_3));
    }

    @OnClick(R.id.tv_mid)
    public void clickMidFee() {
        if(coinType.equalsIgnoreCase("eth")){
            fee = 10;
        }else{
            fee = 24;
        }
        tv_low.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        tv_mid.setBackgroundColor(mContext.getResources().getColor(R.color.blue_e4));
        tv_hig.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        tv_low.setTextColor(mContext.getResources().getColor(R.color.black_3));
        tv_mid.setTextColor(mContext.getResources().getColor(R.color.white));
        tv_hig.setTextColor(mContext.getResources().getColor(R.color.black_3));
    }

    @OnClick(R.id.tv_hig)
    public void clickHigFee() {
        if(coinType.equalsIgnoreCase("eth")){
            fee = 20;
        }else{
            fee = 48;
        }
        tv_low.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        tv_mid.setBackgroundColor(mContext.getResources().getColor(R.color.white));
        tv_hig.setBackgroundColor(mContext.getResources().getColor(R.color.blue_e4));
        tv_low.setTextColor(mContext.getResources().getColor(R.color.black_3));
        tv_mid.setTextColor(mContext.getResources().getColor(R.color.black_3));
        tv_hig.setTextColor(mContext.getResources().getColor(R.color.white));
    }

    @OnClick(R.id.btn_add)
    public void addClick() {
        list.add(list.size(), new SendBean());
        mySendAdapter.addData(list.size());
    }

    private UsbConnectUtils usbConnectUtils;

    private List<SendBean> newOrderList = new ArrayList<>();

    @OnClick(R.id.btn_send)
    public void sendClick() {
        if (mUsbDeviceConnection == null) {
            checkUsb();
            ToastUtils.ShowToast(mContext, "检查usb连接");
            return;
        }
        if(coinType.equalsIgnoreCase("btc")){
            sendBtc();
        }else{
            senEth();
        }

    }

    /**
     * 发送eth
     */
    private void senEth() {
        String ethAddressStr = ethAddress.getText().toString();
        String ethNumStr = ethNum.getText().toString();
        String gsNumStr = gsNum.getText().toString();
        if(!TextUtils.isEmpty(ethAddressStr) && !TextUtils.isEmpty(ethNumStr)
        && !TextUtils.isEmpty(gsNumStr)){
            if(Integer.valueOf(gsNum.getText().toString()) < 50000){
                ToastUtils.ShowToast(mContext,"Gas Limit不低于50000");
                return;
            }
            sendEth2Device(ethAddressStr , ethNumStr , gsNumStr);
        }else{
            ToastUtils.ShowToast(mContext,"检查地址、金额、Gas Limit是否输入");
        }
    }

    /**
     * 发送btc
     */
    private void sendBtc() {
        for (int i = 0; i < list.size(); i++) {
            if (!TextUtils.isEmpty(list.get(i).getAddress()) && !TextUtils.isEmpty(list.get(i).getNum())) {
                newOrderList.add(list.get(i));
            }
        }
        //构建转账数据
        if (newOrderList.size() == 0) {
            ToastUtils.ShowToast(mContext, "请输入地址和金额");
            return;
        }
        creatTX(newOrderList);
        newOrderList.clear();
        sendMsg2Device();
    }

    private DFDialog dfDialogBuilder;

    private void ShowSureDialog() {
        dfDialogBuilder = new DFDialog.Builder(mContext)
                .setTitle("提示")
                .setTwoBtnGone(true)
                .setDissMiss(true)
                .setMessage("请在设备上点击确认")
                .setSure(false)
                .show();
    }

    private void sendSure() {
        DialogUtils.showDialog(mContext);
        int ret = -100;
        TrezorMessageCommon.ButtonAck.Builder buttonAckBuilder = TrezorMessageCommon.ButtonAck.newBuilder();
        TrezorMessageCommon.ButtonAck changePin = buttonAckBuilder.build();
        byte[] init = changePin.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }
        //添加协议
        List<byte[]> bytes = Protocol.encode(27, init);
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据=buttonAck=" + ClsPublicUtils.bytesToHex(sendbytes));
            ret = mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 10000);
        }
        DialogUtils.dismissDialog();
        if (ret > 0) {
            Log.d("dj", "==发送sure成功=" + ret);
        }
        if (serializedTxStr.length() > 0) {
            serializedTxStr.delete(0, serializedTxStr.length());
        }
        getHidMsg();
    }

   /* UsbConnectUtils.OnUsbConnectLishener lishener = new UsbConnectUtils.OnUsbConnectLishener() {
        @Override
        public void onConnect() {
            Log.d("dj", "usb已连接上");
        }

        @Override
        public void onDisconnect() {
            Log.e("dj", "usb断开连接");
        }

        @Override
        public void onReadData(List<byte[]> data) {
            String decodeStr = Protocol.decode(data);
            Log.d("dj", "===decodeStr" + decodeStr);
            try {
                if (Protocol.getType(data) == 3) {//失败
                    TrezorMessageCommon.Failure failure = TrezorMessageCommon.Failure.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(data)));
                    Log.d("dj", "err===" + failure);
                    ToastUtils.ShowToast(mContext, failure.getMessage());
                    if (dfDialogBuilder != null) {
                        dfDialogBuilder.dismiss();
                    }
                } else if (Protocol.getType(data) == 18) {//需要输入pin码
                    showPinDialog();
                } else if (Protocol.getType(data) == 21) {//TxRequest
                    //{"request_type": "TXINPUT","details": {"request_index": 0}}
                    TrezorMessageBitcoin.TxRequest txRequest = TrezorMessageBitcoin.TxRequest.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(data)));
                    String publicKeyJson = JsonFormat.printToString(txRequest);
                    if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXINPUT_VALUE) {
                        sendTxInput(true, txRequest.getDetails().getRequestIndex());
                    } else if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXOUTPUT_VALUE) {
                        sendTxInput(false, txRequest.getDetails().getRequestIndex());
                    } else if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXFINISHED_VALUE) {
                        ToastUtils.ShowToast(mContext, "转账成功");
                    }
                    Log.d("dj", "==public=key=json=" + publicKeyJson);
                    Log.d("dj", "==public=key==" + txRequest);
                } else if (Protocol.getType(data) == 26) {//ButtonRequest
                    ShowSureDialog();
                    sendSure();
                }

            } catch (InvalidProtocolBufferException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };*/

    /**
     * 发送input/output，按单个发送
     */
    private void sendTxInput(boolean isInput, int pos) {
        DialogUtils.showDialog(mContext);

        TrezorMessageBitcoin.TxAck.Builder txAckBuilder = TrezorMessageBitcoin.TxAck.newBuilder();

        TrezorMessageBitcoin.TxAck.TransactionType.Builder builder = TrezorMessageBitcoin.TxAck.TransactionType.newBuilder();
        if (isInput) {
            builder.addInputs(txInputTypes.get(pos));
        } else {
            builder.addOutputs(txOutputTypes.get(pos));
        }
        txAckBuilder.setTx(builder.build());
        Log.d("dj", "=====input=====" + txAckBuilder.build());
        byte[] init = txAckBuilder.build().toByteArray();//转成16进制

        /*if (!usbConnectUtils.isConnected()) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }
        //添加协议 22 = TxAck
        List<byte[]> bytes = Protocol.encode(22, init);
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            int write = usbConnectUtils.write(bytes.get(i));
            if (write >= 0) {
                showToast("发送成功" + write);
            } else {
                DialogUtils.dismissDialog();
            }
        }*/
        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }
        List<byte[]> bytes = Protocol.encode(22, init);
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据=input=" + ClsPublicUtils.bytesToHex(sendbytes));
            mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 10000);
        }
        DialogUtils.dismissDialog();
        getHidMsg();
    }

    private boolean isDestory = true;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            String info = (String) msg.obj;
            if (msg.what == 102) {
                /*String str = null;
                try {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                        str = ClsPublicUtils.bytesToHex(android.util.Base64.decode(info, Base64.DEFAULT));
//                        str = ClsPublicUtils.bytesToHex(info.getBytes(StandardCharsets.ISO_8859_1));
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }*/
                Log.d("dj", "====handlemsg====" + info);
                presenter.broadcastBtcTx(info);
            }

        }
    };

    private StringBuilder serializedTxStr = new StringBuilder();

    private void getMsg() {
        new Thread(() -> {
            do {
                List<byte[]> byteRe = new ArrayList<>();
                try {
                    boolean isContinue = true;
                    while (isContinue) {
                        byte[] recByte = new byte[64];
                        mUsbDeviceConnection.bulkTransfer(usbEndpointIn, recByte, recByte.length, 10000);
                        if (Protocol.hasHead(recByte)) {
                            byteRe.add(recByte);
                        } else {
                            isContinue = false;
                        }
                    }

                    if (byteRe.size() > 0) {
                        if (Protocol.getType(byteRe) == 21) {//TxRequest
                            //{"request_type": "TXINPUT","details": {"request_index": 0}}
                            mHandler.postDelayed(() -> {
                                if (dfDialogBuilder != null) {
                                    dfDialogBuilder.dismiss();
                                }
                            }, 100);
                            TrezorMessageBitcoin.TxRequest txRequest = TrezorMessageBitcoin.TxRequest.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(byteRe)));
                            String publicKeyJson = JsonFormat.printToString(txRequest);
                            if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXINPUT_VALUE) {
                                sendTxInput(true, txRequest.getDetails().getRequestIndex());
                            } else if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXOUTPUT_VALUE) {
                                sendTxInput(false, txRequest.getDetails().getRequestIndex());
                            } else if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXFINISHED_VALUE) {
                                isDestory = false;
                                ToastUtils.ShowToast(mContext, "签名成功，正在广播");
                                Log.e("dj", "签名成功，正在广播");
                            }
                            Log.d("dj", "==public=key=json=" + publicKeyJson);
                            Log.d("dj", "==public=key==" + txRequest);
                            if (txRequest.getSerialized() != null && !TextUtils.isEmpty(txRequest.getSerialized().getSerializedTx().toString())) {
                                //获取到的是16进制字符串
//                                serializedTxStr.append(ClsPublicUtils.byteStrToString(txRequest.getSerialized().getSerializedTx(), StandardCharsets.ISO_8859_1));
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                                    Log.d("dj", "==签名交易过程==" + new String(txRequest.getSerialized().getSerializedTx().toByteArray()));
                                }
                                Log.d("dj", "==签名交易过程==" + serializedTxStr.toString());
                                if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXFINISHED_VALUE) {
                                    Log.d("dj", "==签名交易广播==" + serializedTxStr.toString());
                                    Message message = mHandler.obtainMessage();
                                    message.what = 102;
                                    message.obj = serializedTxStr.toString();
                                    mHandler.sendMessage(message);
                                }

                            }
                        } else if (Protocol.getType(byteRe) == 26) {//ButtonRequest
                            ShowSureDialog();
                            sendSure();
                            isDestory = false;
                        } else if (Protocol.getType(byteRe) == 3) {
                            TrezorMessageCommon.Failure failure = TrezorMessageCommon.Failure.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(byteRe)));
                            Log.d("dj", "err===" + failure);
                            ToastUtils.ShowToast(mContext, failure.getMessage());
                            mHandler.postDelayed(() -> {
                                if (dfDialogBuilder != null) {
                                    dfDialogBuilder.dismiss();
                                }
                                ToastUtils.ShowToast(mContext, "签名失败");
                                isDestory = false;
                            }, 100);
                        }

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } while (isDestory);
        }).start();
    }

    /**
     * 根据发送的金额和地址来构建转帐数据
     */
    /**
     * 构建转账数据
     *
     * <p>
     * <p>
     * 转账的步骤：
     * 1.根据需要转出到的地址和金额，构建outputs
     * 2.根据outputs总额，构建inputs，判断总额是否足够
     * 3.称重，然后根据费率计算手续费
     * 4.得到手续费后，校验inputs是否满足交易所需（inputs >= outputs + fee）
     * 4.1不满足需求则从utxos中取余额出来再次添加到inputs中，然后循环3,4
     * 5.计算是否需要找零（inputs > outputs + fee）
     * 5.1需要找零则在outputs中增加找零地址,由于地址增加，则需要重新执行3,4,5
     * 6.得到最后的交易数据
     * tips:
     * 1.注意BTC个数和聪(Sat)之间的转换 1btc = 10^8 Sat
     * 2.utxos建议根据value升序排列
     *
     * @memberof BlockchainTool
     */
    private List<TrezorMessageBitcoin.TxAck.TransactionType.TxInputType> txInputTypes = new ArrayList<>();
    private List<TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType> txOutputTypes = new ArrayList<>();
    private BigDecimal inputAmounts;
    private BigDecimal outAmounts;

    private void creatTX(List<SendBean> sendBeans) {
        if (mUtxoBeanList == null || mUtxoBeanList.size() == 0) {
            ToastUtils.ShowToast(mContext, "没有可用资产");
            return;
        }

        //outputs ,inputs

        //先对资产value进行排序，升序
        Collections.sort(mUtxoBeanList, ((o1, o2) -> (int) (Double.parseDouble(o1.getValue()) - Double.parseDouble(o2.getValue()))));
        //构建output
        outAmounts = new BigDecimal(0);
        buildOutPut(sendBeans);
        //构建input
        buildInput();

        //输出大于输入，提示余额不足
        if (outAmounts.compareTo(inputAmounts) > 0) {
            ToastUtils.ShowToast(mContext, "余额不足");
            return;
        }
        //计算找零
        countChange();
    }

    /**
     * 计算找零
     */
    private void countChange() {
        long amount = (long) Double.parseDouble(String.valueOf(BigdecimalUtils.getBigDecimalPointNum(inputAmounts.subtract(outAmounts), 2)));
        if (amount > 0) {//给的钱-输出的钱大于0 则需要找零
            TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType.Builder builder = TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType.newBuilder();
            List<Integer> address = new ArrayList<>(5);
            address.add(UCaculateUtils.changeNum(44));
            address.add(UCaculateUtils.changeNum(0));
            address.add(UCaculateUtils.changeNum(0));
            address.add(UCaculateUtils.changeNum(1, false));
            address.add(UCaculateUtils.changeNum(0, false));
            builder.addAllAddressN(address)
                    .setAmount(amount)
                    .setScriptType(TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType.OutputScriptType.PAYTOADDRESS);
            txOutputTypes.add(builder.build());
            /*outputs变化，重新称重,并构建先清空再构建inputs*/
            buildInput();
        }
    }


    private static final int BTC_2_SAT = 1_0000_0000;

    /**
     * 构建output
     */
    private void buildOutPut(List<SendBean> sendBeans) {
        if (txOutputTypes.size() > 0) {
            txOutputTypes.clear();
        }
        for (SendBean sendBean : sendBeans) {
            //每个地址转出的钱
            BigDecimal num2Sat = BigdecimalUtils.getBigDecimalPrice(sendBean.getNum(), 8).multiply(new BigDecimal(BTC_2_SAT));
            TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType.Builder builder = TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType.newBuilder();
            builder.setAddress(sendBean.getAddress())
                    .setAmount((long) Double.parseDouble(sendBean.getNum()))
                    .setScriptType(TrezorMessageBitcoin.TxAck.TransactionType.TxOutputType.OutputScriptType.PAYTOADDRESS);
            txOutputTypes.add(builder.build());
            outAmounts = outAmounts.add(num2Sat);
        }
    }

    /**
     * 构建input
     */
    private void buildInput() {
        if (txInputTypes.size() > 0) {
            txInputTypes.clear();
        }
        inputAmounts = new BigDecimal(0);
        for (UtxoBean utxoBean : mUtxoBeanList) {
            if ((inputAmounts).compareTo(weight()) >= 0) {
                break;
            }
            TrezorMessageBitcoin.TxAck.TransactionType.TxInputType.Builder builder = TrezorMessageBitcoin.TxAck.TransactionType.TxInputType.newBuilder();
            builder.addAllAddressN(UCaculateUtils.parsePath(utxoBean.getPath()))
                    .setAmount(Long.parseLong(utxoBean.getValue()))
                    .setPrevHash(ByteString.copyFrom(ClsPublicUtils.hexToBytes(utxoBean.getTxid())))
                    .setPrevIndex(utxoBean.getVout())
                    .setScriptType(TrezorMessageBitcoin.InputScriptType.SPENDP2SHWITNESS);

            inputAmounts = inputAmounts.add(BigdecimalUtils.getBigDecimalPrice(utxoBean.getValue(), BigdecimalUtils.getPointNum(utxoBean.getValue())));
            txInputTypes.add(builder.build());
        }
    }

    /**
     * 称重
     */
    private BigDecimal weight() {
        BigDecimal sizeIn = new BigDecimal(txInputTypes.size()).multiply(new BigDecimal(148));
        BigDecimal sizeOut = new BigDecimal(txOutputTypes.size()).multiply(new BigDecimal(34));
        BigDecimal fees = sizeIn.add(sizeOut).add(new BigDecimal(10)).multiply(new BigDecimal(fee));
        return outAmounts.add(fees);
    }

    private void checkUsb() {
        if (usbManager == null) {
            return;
        }
        HashMap<String, UsbDevice> deviceHashMap = usbManager.getDeviceList();
        Iterator<UsbDevice> deviceIterator = deviceHashMap.values().iterator();
        ArrayList<String> usbDeviceList = new ArrayList<>();//存放usb数量
        while (deviceIterator.hasNext()) {
            UsbDevice device = deviceIterator.next();
            usbDeviceList.add(String.valueOf(device.getVendorId()));
            usbDeviceList.add(String.valueOf(device.getProductId()));
            if (device.getVendorId() == 0x1209 && device.getProductId() == 0x53C1) {//找到我们的usb设备
                ToastUtils.ShowToast(mContext, "找到了对应的usb设备（硬件钱包）");
                mUsbDevice = device;
            }
        }
        //请求权限
        if (mUsbDevice == null) {
            ToastUtils.ShowToast(mContext, "没找到对应的usb设备");
            return;
        }
        if (usbManager.hasPermission(mUsbDevice)) {
            findIntfAndEpt();
        } else {
            getUsbPermission(mUsbDevice);
        }
    }

    /**
     * 寻找接口和分配结点
     */
    private UsbEndpoint usbEndpointIn;
    private UsbEndpoint usbEndpointOut;

    private void findIntfAndEpt() {
        if (mUsbDevice == null) {
            return;
        }
        if (mUsbDevice.getInterfaceCount() <= 0) {
            return;
        }
        mUsbInterface = mUsbDevice.getInterface(0);
        //打开设备，获取UsbDeviceConnection对象，连接设备，用于后面的通讯
        UsbDeviceConnection usbDeviceConnection = usbManager.openDevice(mUsbDevice);
        if (usbDeviceConnection == null) {
            return;
        }
        if (usbDeviceConnection.claimInterface(mUsbInterface, true)) {
            //找到接口
            mUsbDeviceConnection = usbDeviceConnection;
            //用于UsbDeviceConnection与UsbInterface进行端点设置和通讯
            if (mUsbInterface.getEndpoint(0) != null) {
                usbEndpointIn = mUsbInterface.getEndpoint(0);
            }
            if (mUsbInterface.getEndpoint(1) != null) {
                usbEndpointOut = mUsbInterface.getEndpoint(1);
            }
        } else {
            //断开连接
            usbDeviceConnection.close();
        }
    }

    /**
     * 给u盾发送数据
     */
    private void sendMsg2Device() {
        int ret = -100;
        DialogUtils.showDialog(mContext);
        TrezorMessageBitcoin.SignTx.Builder signTxBuilder = TrezorMessageBitcoin.SignTx.newBuilder();
        signTxBuilder.setOutputsCount(txOutputTypes.size());
        signTxBuilder.setInputsCount(txInputTypes.size());
        TrezorMessageBitcoin.SignTx signTx = signTxBuilder.build();

        byte[] init = signTx.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }
        //添加协议 SignTx = 15
        List<byte[]> bytes = Protocol.encode(15, init);
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据==" + ClsPublicUtils.bytesToHex(sendbytes));
            ret = mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 10000);
        }
        DialogUtils.dismissDialog();
        getHidMsg();
    }

    /**
     * 给u盾发送eth数据
     */
    private void sendEth2Device(String addressStr,String ethStr,String gsStr) {
//        Web3j web3j = Web3jFactory.build(new HttpService("https://ropsten.infura.io/"));
        int ret = -100;
        DialogUtils.showDialog(mContext);
        TrezorMessageEthereum.EthereumSignTx.Builder signTxBuilder = TrezorMessageEthereum.EthereumSignTx.newBuilder();
        List<Integer> address = new ArrayList<>(5);
        address.add(UCaculateUtils.changeNum(44));
        address.add(UCaculateUtils.changeNum(60));
        address.add(UCaculateUtils.changeNum(0));
        address.add(UCaculateUtils.changeNum(0, false));
        address.add(UCaculateUtils.changeNum(0, false));
        signTxBuilder.addAllAddressN(address);
        signTxBuilder.setTo(addressStr);
        signTxBuilder.setChainId(1);
       /* EthGetTransactionCount ethGetTransactionCount = null;
        try {
            ethGetTransactionCount = web3j.ethGetTransactionCount(
                    addressStr, DefaultBlockParameterName.LATEST).send();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BigInteger nonce = Objects.requireNonNull(ethGetTransactionCount).getTransactionCount();nonce.toString(16)*/
        signTxBuilder.setNonce(ByteString.copyFrom(ClsPublicUtils.hexToBytes(ClsPublicUtils.numToHex16(0))));//交易次数
        signTxBuilder.setGasLimit(ByteString.copyFrom(Convert.toWei(gsStr,Convert.Unit.GWEI).toBigInteger().toByteArray()));
        signTxBuilder.setGasPrice(ByteString.copyFrom(Convert.toWei(String.valueOf(fee),Convert.Unit.GWEI).toBigInteger().toByteArray()));
//        signTxBuilder.setValue(ByteString.copyFrom(Numeric.toBytesPadded(Convert.toWei(ethStr,Convert.Unit.ETHER).toBigInteger(), 32)));
        signTxBuilder.setValue(ByteString.copyFrom(Convert.toWei(ethStr,Convert.Unit.ETHER).toBigInteger().toByteArray()));
        TrezorMessageEthereum.EthereumSignTx signTx = signTxBuilder.build();

        byte[] init = signTx.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }
        //添加协议 EthereumSignTx = 58
        List<byte[]> bytes = Protocol.encode(58, init);
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据==" + ClsPublicUtils.bytesToHex(sendbytes));
            ret = mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 10000);
        }
        DialogUtils.dismissDialog();
        if(ret < 0){
            ToastUtils.ShowToast(mContext,"发送数据失败");
            return;
        }
        getHidMsg();
    }

    /**
     * 获取u盾的消息
     */
    @SuppressLint("StaticFieldLeak")
    public void getHidMsg() {
        new AsyncTask<String, Integer, List<byte[]>>() {
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                //开始接受信息
                DialogUtils.showDialog(mContext);
            }

            @Override
            protected List<byte[]> doInBackground(String... params) {
                List<byte[]> byteRe = new ArrayList<>();
                try {
                    boolean isContinue = true;
                    while (isContinue) {
                        byte[] recByte = new byte[64];
                        mUsbDeviceConnection.bulkTransfer(usbEndpointIn, recByte, recByte.length, 10000);
                        if (Protocol.hasHead(recByte)) {
                            byteRe.add(recByte);
                        } else {
                            isContinue = false;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return byteRe;
            }

            @SuppressLint("NewApi")
            @Override
            protected void onPostExecute(List<byte[]> bytes) {
                if (bytes == null || bytes.size() == 0) {
                    //接受信息失败
                    DialogUtils.dismissDialog();
                    return;
                }
                DialogUtils.dismissDialog();
                Log.d("dj", "==解码=前=" + ClsPublicUtils.bytesToHex(bytes.get(0)));
                Log.d("dj", "==解码=后=" + Protocol.decode(bytes));
                try {
                    if (Protocol.getType(bytes) == 3) {//失败
                        TrezorMessageCommon.Failure failure = TrezorMessageCommon.Failure.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        Log.d("dj", "err===" + failure);
                        ToastUtils.ShowToast(mContext, failure.getMessage());
                        if (dfDialogBuilder != null) {
                            dfDialogBuilder.dismiss();
                        }
                    } else if (Protocol.getType(bytes) == 18) {//需要输入pin码
                        showPinDialog();
                    } else if (Protocol.getType(bytes) == 21) {//TxRequest
                        //{"request_type": "TXINPUT","details": {"request_index": 0}}
                        if (dfDialogBuilder != null) {
                            dfDialogBuilder.dismiss();
                        }
                        TrezorMessageBitcoin.TxRequest txRequest = TrezorMessageBitcoin.TxRequest.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        String publicKeyJson = JsonFormat.printToString(txRequest);
                        if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXINPUT_VALUE) {
                            sendTxInput(true, txRequest.getDetails().getRequestIndex());
                        } else if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXOUTPUT_VALUE) {
                            sendTxInput(false, txRequest.getDetails().getRequestIndex());
                        } else if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXFINISHED_VALUE) {
                            ToastUtils.ShowToast(mContext, "转账成功");
                        }
                        Log.d("dj", "==public=key==" + txRequest);
                        if (txRequest.getSerialized() != null && !TextUtils.isEmpty(txRequest.getSerialized().getSerializedTx().toString())) {
                            //获取到的是16进制字符串 getBytes(CharEncoding.ISO_8859_1)
//                            String str = encodeToString(txRequest.getSerialized().getSerializedTx().toByteArray(),android.util.Base64.DEFAULT);
//                            ByteString.copyFrom(txRequest.getSerialized().getSerializedTx().toByteArray());
                            //Log.e("dj","==pk=="+ClsPublicUtils.bytesToHex(android.util.Base64.decode(encodeToString( publicKey.getNode().getPublicKey().toByteArray(),android.util.Base64.DEFAULT), Base64.DEFAULT)));
                            serializedTxStr.append(ClsPublicUtils.bytesToHex(android.util.Base64.decode(encodeToString(txRequest.getSerialized().getSerializedTx().toByteArray(), android.util.Base64.DEFAULT), Base64.DEFAULT)));
//                            serializedTxStr.append(str);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                                Log.d("dj", "==签名交易过程=getHidMsg1=" + serializedTxStr.toString());
                            }
                            if (txRequest.getRequestType().getNumber() == TrezorMessageBitcoin.TxRequest.RequestType.TXFINISHED_VALUE) {
                                Log.d("dj", "==签名交易广播==" + serializedTxStr.toString());
                                Message message = mHandler.obtainMessage();
                                message.what = 102;
                                message.obj = serializedTxStr.toString();
                                mHandler.sendMessage(message);
                            }

                        }
                    } else if (Protocol.getType(bytes) == 26) {//ButtonRequest
                        ShowSureDialog();
                        sendSure();
                    }else if(Protocol.getType(bytes) == 59){//EthereumTxRequest = 59
                        if (dfDialogBuilder != null) {
                            dfDialogBuilder.dismiss();
                        }
                        TrezorMessageEthereum.EthereumTxRequest ethereumTxRequest = TrezorMessageEthereum.EthereumTxRequest.parseFrom(ClsPublicUtils.hexToBytes(Protocol.decode(bytes)));
                        Log.d("dj","===eth===="+ethereumTxRequest);
//                        Message message = mHandler.obtainMessage();
//                        message.what = 103;
//                        message.obj = ethereumTxRequest.get();
//                        mHandler.sendMessage(message);
                    }

                } catch (InvalidProtocolBufferException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }.execute();
    }

    /**
     * 弹出输入pin码的弹窗
     */
    private InputPinDialog.Builder mDialog;

    private void showPinDialog() {
        if (mDialog == null) {
            mDialog = new InputPinDialog.Builder(mContext, R.style.OrderDialogStyle);
        }
        mDialog.setOnSureBtnClick(new InputPinDialog.OnSureBtnClick() {
            @Override
            public void onClickSure(String numTV) {
                sendPin(numTV);
                mDialog.dismiss();
            }
        });
        Log.d("dj", "请输入pin码");
        mDialog.creater().show();
    }

    /**
     * 发送pin给u盾
     */
    private void sendPin(String numTV) {
        TrezorMessageCommon.PinMatrixAck.Builder pinMatrixAckBuilder = TrezorMessageCommon.PinMatrixAck.newBuilder();
        pinMatrixAckBuilder.setPin(numTV);
        TrezorMessageCommon.PinMatrixAck pinMatrixAck = pinMatrixAckBuilder.build();//组装成对应的protobuf文件中的方法
        Log.d("dj", "===publickeyjson===" + JsonFormat.printToString(pinMatrixAck));
        byte[] init = pinMatrixAck.toByteArray();//转成16进制

        if (mUsbDeviceConnection == null) {
            ToastUtils.ShowToast(mContext, "没有建立连接");
            return;
        }

        //添加协议 19 发送pin码
        List<byte[]> bytes = Protocol.encode(19, pinMatrixAck.toByteArray());
        // 1,发送准备命令
        //通过usb hid传输数据给u盾
        for (int i = 0; i < bytes.size(); i++) {
            byte[] sendbytes = bytes.get(i);
            Log.d("dj", "==发送数据==" + ClsPublicUtils.bytesToHex(sendbytes));
            mUsbDeviceConnection.bulkTransfer(usbEndpointOut, sendbytes, sendbytes.length, 5000);
        }
        getHidMsg();
    }

    private Receiver mUsbReceiver;

    //开始申请USB权限
    private void getUsbPermission(UsbDevice mUSBDevice) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(BeemIntent.ACTION_USB_INTENT), 0);
        IntentFilter filter = new IntentFilter(BeemIntent.ACTION_USB_INTENT);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
        mUsbReceiver = new Receiver();
        mContext.registerReceiver(mUsbReceiver, filter);
        usbManager.requestPermission(mUSBDevice, pendingIntent); // 该代码执行后，系统弹出一个对话框/等待权限
    }

    private class Receiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (BeemIntent.ACTION_USB_INTENT.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
                            && mUsbDevice.equals(device)) {
                        //TODO 授权成功，操作USB设备
                        ToastUtils.ShowToast(mContext, "usb授权成功");
                    } else {
                        //用户点击拒绝了
                        ToastUtils.ShowToast(mContext, "拒绝usb授权");
                    }
                }
            }
        }
    }

    private class UpdataCoinTypeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Objects.requireNonNull(action).equals(BeemIntent.ACTION_UPDATE_CION_TYPE_INTENT)) {
                coinType = intent.getStringExtra("coinType");
                changeView();
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mUsbReceiver != null) {
            mContext.unregisterReceiver(mUsbReceiver);
        }
        if(mUpdataReceiver != null){
            mContext.unregisterReceiver(mUpdataReceiver);
        }
        if (usbConnectUtils != null) {
            usbConnectUtils.release(true);
        }
    }

}
